Skip to content

Add the rite_calendar_test object type to the LiturgicalCalendar model - #31

Merged
JohnRDOrazio merged 1 commit into
mainfrom
feat/rite-calendar-test-type
Aug 16, 2026
Merged

Add the rite_calendar_test object type to the LiturgicalCalendar model#31
JohnRDOrazio merged 1 commit into
mainfrom
feat/rite-calendar-test-type

Conversation

@JohnRDOrazio

@JohnRDOrazio JohnRDOrazio commented Aug 16, 2026

Copy link
Copy Markdown
Member

What broke

LiturgicalCalendarAPI #785 introduced a new OpenFGA object type, rite_calendar_test, and started querying it from ResourceAdminService::VIEWER_OBJECT_TYPES and TEST_OBJECT_TYPES. It generalises general_roman_calendar_test, whose single fixed id (general_roman_calendar) could only ever name the Roman rite-level calendar; the new type's object id is the bare rite, so rite_calendar_test:roman succeeds it and rite_calendar_test:ambrosian is the scope the generalisation exists for.

The type was never added to the deployed model. #785 edited LiturgicalCalendarAPI/scripts/openfga-model.additive.json — a file that repo's own runbook (docs/ops/rbac-create-governance-runbook.md, lines 16-19) already declares dead:

the OpenFGA model now lives in cdcf-infra (auth/models/LiturgicalCalendar.json) […] Model changes go through a PR in cdcf-infra, followed by an operator running ./setup-openfga.sh --target production --create-litcal-store

No such PR was ever opened. This is it. (That dead file is being deleted in a companion PR on the API side, since looking like a live surface is exactly how this happened.)

Observable symptom — global, not scoped

listObjects on an unknown type returns 400 type_not_found, which the API's OpenFgaClient surfaces as a RuntimeException. In ResourceAdminService the foreach over object types sits inside a single try, and the catch (\RuntimeException) returns array_fill_keys(VIEWER_OBJECT_TYPES, []) — so one unknown type empties every type's scope list, for every user. Dashboard card gating therefore collapses globally, not just for rite-scoped tests.

Confirmed against a dev store: its latest model contains user, wider_region, national_calendar, diocesan_calendar, general_roman_calendar, national_calendar_test, diocesan_calendar_test, general_roman_calendar_test — and no rite_calendar_test.

Downstream LiturgicalCalendarFrontend e2e specs this unblocks:

  • rbac/07-dashboard-card-scoping:143
  • rbac/12
  • rbac/13:153 and rbac/13:201
  • rbac/15-dashboard-tests-card-matrix:36

The change

rite_calendar_test with relations admin / editor / viewer, identical to general_roman_calendar_test: editor is a union including admin, viewer a union including both, each directly relatable to user.

That relation set is not a guess. It is:

  • what the API actually queries — listObjects for viewer, editor and admin (ResourceAdminService), and OpenFgaAuthorizationMiddleware checking admin for PUT/DELETE and editor for PATCH;
  • what LiturgicalCalendarAPI/docs/ops/test-scope-migration-runbook.md Step 1 specifies — "added […] alongside general_roman_calendar_test, with an identical relation set";
  • consistent with the sibling national_calendar_test / diocesan_calendar_test types already in this file.

No deleter. The consumer's own expectations file forbids that relation model-wide ("forbidden_relations": {"*": ["deleter"]}), and the dead file's copy of the type carries one — one more reason not to have mirrored it verbatim.

Purely additive. general_roman_calendar_test is untouched: pre-migration tuples on it must keep authorizing until scripts/migrate-rite-test-tuples.php --apply --prune has run in every environment, and the API still accepts the old type everywhere.

auth/handoffs/liturgicalcalendar.md gets a note rather than an edited type list — the list there describes deployed model 01KW4FW2ZCT1E693PY8D9TJEFM, which genuinely does not contain this type yet.

Verification

Not by inspection — against the consumer contract itself, using the registry entry from #30:

# main's model
✗ [LiturgicalCalendarAPI] required_types: type "rite_calendar_test" not found in model   (exit 1)

# this branch's model
✓ No violations. LiturgicalCalendar satisfies LiturgicalCalendarAPI's expectations.      (exit 0)

./auth/validate-expectations.selftest.sh — all 21 cases behave as declared.

Coordination with #30

#30 should not merge before this PR. auth/models/consumers.json on main is still [], so validate-models on this PR passes trivially (empty registry = nothing to contradict) — its green tells you nothing, hence the manual run above. #30 registers LiturgicalCalendarAPI against development's expectations file, which already lists rite_calendar_test in required_types. #30's own CI ran on 2026-08-05, before that line existed; re-run today it goes red, and merging it first turns main red on the push-triggered run. Landing this first makes #30 green again with no change to #30 itself.

Deploy step required — this PR alone changes nothing live

Merging only updates the model file. An operator must then, per auth/README.md:

cd /opt/cdcf-auth/auth
./setup-openfga.sh --target production --create-litcal-store

The lock guard will refuse (exit 7) if the store's latest model does not match LiturgicalCalendar.lock.json; otherwise it uploads and prints the new model ID plus the lock JSON to commit. That lock update is a follow-up PR — this one deliberately leaves LiturgicalCalendar.lock.json alone, since the script never writes it and the ID is not knowable before the upload. Any consumer pinning OPENFGA_MODEL_ID needs the new ID too, and the liturgicalcalendar.md handoff note should be resolved at the same time.

Local dev stacks (including the frontend e2e store) pick the type up by re-running setup-openfga.sh --target local against a clone of this repo after merge — the e2e specs above stay red until that happens.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added a test liturgical calendar access type with administrator, editor, and viewer roles.
    • Editors inherit administrator permissions, while viewers inherit editor and administrator access.
    • All roles support direct user assignments.
  • Documentation

    • Documented the type’s relationships, object ID format, deployment steps, and required follow-up configuration updates.

LiturgicalCalendarAPI#785 introduced a new FGA object type,
`rite_calendar_test`, and started querying it from
`ResourceAdminService::VIEWER_OBJECT_TYPES` / `TEST_OBJECT_TYPES`. It
generalises `general_roman_calendar_test`, whose single fixed id
(`general_roman_calendar`) could only ever name the Roman rite-level
calendar; the new type's object id is the bare rite, so
`rite_calendar_test:roman` succeeds it and `rite_calendar_test:ambrosian`
is the scope the generalisation exists for.

The type was never added here. #785 edited
`LiturgicalCalendarAPI/scripts/openfga-model.additive.json`, a file that
repo's own runbook already declares dead — model changes go through a PR
in this repo, followed by an operator upload on the VPS. So the type
exists in the API's allow-lists and in nothing that is deployed.

Relations are `admin` / `editor` / `viewer`, identical to
`general_roman_calendar_test`: `editor` is a union including `admin`,
`viewer` a union including both, each directly relatable to `user`.
That is what the API actually queries (listObjects for `viewer`,
`editor`, and `admin`; the authorization middleware checks `admin` for
PUT/DELETE and `editor` for PATCH), and it is what
`LiturgicalCalendarAPI/docs/ops/test-scope-migration-runbook.md` Step 1
specifies. No `deleter`: the consumer's own expectations file forbids
that relation model-wide, and the dead file's copy of the type carries
one — one more reason not to have mirrored it.

Purely additive. `general_roman_calendar_test` is untouched, because
pre-migration tuples on it must keep authorizing until
`scripts/migrate-rite-test-tuples.php --apply --prune` has run
everywhere.

Verified against the consumer contract rather than by inspection: with
the registry entry from #30, `validate-expectations.sh` reports
`required_types: type "rite_calendar_test" not found in model` (exit 1)
against main's model, and `satisfied` (exit 0) against this one.

`LiturgicalCalendar.lock.json` is deliberately not touched — the model
ID is whatever the store returns on upload, and setup-openfga.sh reports
the lock JSON for a human to commit afterwards.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Aug 16, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 01917bf6-febd-4a59-b80f-27dd92c18b1f

📥 Commits

Reviewing files that changed from the base of the PR and between 5ce7ecc and 2bd015c.

📒 Files selected for processing (2)
  • auth/handoffs/liturgicalcalendar.md
  • auth/models/LiturgicalCalendar.json

Included review availability: Your plan includes up to 1 review per rolling hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

The authorization model adds the rite_calendar_test type with inherited admin, editor, and viewer access. The handoff document records that the type is not deployed and lists the required production deployment and model lock updates.

Changes

Liturgical calendar authorization

Layer / File(s) Summary
Define and record the test authorization type
auth/models/LiturgicalCalendar.json, auth/handoffs/liturgicalcalendar.md
The model adds rite_calendar_test with admin, editor, and viewer relations. The handoff documents its undeployed status and required deployment follow-up.

Estimated code review effort: 2 (Simple) | ~10 minutes

Merge Risk: ⚪ Minimal · up to 2bd01

This PR adds the missing calendar object type, and no actionable merge-blocking risk remains; it is merge-ready after normal checks and review.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the addition of the rite_calendar_test object type to the LiturgicalCalendar model.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/rite-calendar-test-type

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@JohnRDOrazio
JohnRDOrazio merged commit e735e7f into main Aug 16, 2026
2 checks passed
@JohnRDOrazio
JohnRDOrazio deleted the feat/rite-calendar-test-type branch August 16, 2026 17:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant